package com.ruoyi.waterManagement.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.waterManagement.mapper.RelZQMapper;
import com.ruoyi.waterManagement.service.IRelZQService;
import com.ruoyi.waterManagement.util.ArithmeticUtils;
import com.ruoyi.waterManagement.util.BigDecimalUtil;
import com.ruoyi.waterManagement.util.LeastSquareMethod;
import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.core.domain.business.waterManagement.RelZQ;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;

/**
 * 水位流量关系对照Service业务层处理
 *
 * @author hwd
 * @date 2023-02-23
 */
@Service
public class RelZQServiceImpl extends ServiceImpl<RelZQMapper,RelZQ> implements IRelZQService
{
    @Autowired
    private RelZQMapper relZQMapper;

    /**
     * 查询水位流量关系对照
     *
     * @param statCd 水位流量关系对照主键
     * @return 水位流量关系对照
     */
    @Override
    public RelZQ selectRelZQByStatCd(String statCd)
    {
        return relZQMapper.selectRelZQByStatCd(statCd);
    }

    /**
     * 查询水位流量关系对照列表
     *
     * @param relZQ 水位流量关系对照
     * @return 水位流量关系对照
     */
    @Override
    public List<RelZQ> selectRelZQList(RelZQ relZQ)
    {
        return relZQMapper.selectRelZQList(relZQ);
    }

    /**
     * 新增水位流量关系对照
     *
     * @param relZQ 水位流量关系对照
     * @return 结果
     */
    @Override
    public int insertRelZQ(RelZQ relZQ)
    {
        return relZQMapper.insertRelZQ(relZQ);
    }

    /**
     * 修改水位流量关系对照
     *
     * @param relZQ 水位流量关系对照
     * @return 结果
     */
    @Override
    public int updateRelZQ(RelZQ relZQ)
    {
        return relZQMapper.updateRelZQ(relZQ);
    }

    /**
     * 批量删除水位流量关系对照
     *
     * @param statCds 需要删除的水位流量关系对照主键
     * @return 结果
     */
    @Override
    public int deleteRelZQByStatCds(String[] statCds)
    {
        return relZQMapper.deleteRelZQByStatCds(statCds);
    }

    /**
     * 删除水位流量关系对照信息
     *
     * @param statCd 水位流量关系对照主键
     * @return 结果
     */
    @Override
    public int deleteRelZQByStatCd(String statCd)
    {
        return relZQMapper.deleteRelZQByStatCd(statCd);
    }


    @Override
    public List<RelZQ> selCurvNmByStatCd(String statCd) {
        return relZQMapper.selCurvNmByStatCd(statCd);
    }

    @Override
    public Map<Integer, Map<Integer, BigDecimal>> selectRelZQListMap(List<RelZQ> relZQS1) {
        //存到map中
        Map<Integer, Map<Integer, BigDecimal>> maps = new HashMap();
        Map<Double,BigDecimal> bigDecimalMap=new HashMap<>();
        //将水位流量存到map中
        for (int i = 0; i < relZQS1.size(); i++) {
            double z= ArithmeticUtils.mul(relZQS1.get(i).getCurLevel().doubleValue(),100);
            bigDecimalMap.put(z,relZQS1.get(i).getCurFlow());
        }
        //获取最大的水位值
        RelZQ z=relZQS1.get(relZQS1.size()-1);
        //获取最大值
        int a= new BigDecimal(String.valueOf(100)).multiply(z.getCurLevel()).intValue();
        int g = a% 10;
        //十位
        int s = (a/ 10) % 10;
        //百位
        int c = (a / 100) % 10;
        //int a= new BigDecimal(String.valueOf(100)).multiply(relZQS1.get(i).getZ()).intValue();
        boolean flag = false;   //标识变量
        int big =0;
        if (g!=9){
            a=a+9-g;
        }
        Map<Integer, BigDecimal> map = new HashMap<>();
        for (int i = 0; i < 9; i++) {
            map=new HashMap<>();
            for (int j = 0; j <10 ; j++) {
                map=new HashMap<>();
                for (int k = 0; k <10 ; k++) {
                    flag=false;
                    Iterator<Double> iter = bigDecimalMap.keySet().iterator();
                    while (iter.hasNext()) {
                        double y=100*i+10*j+k;
                        double key = iter.next();
                        if (key==y){
                            map.put(k,bigDecimalMap.get(key));
                            flag=true;
                            break;
                        }
                    }
                    if (!flag){
                        map.put(k,new BigDecimal("0.0"));
                    }
                    maps.put(100*i+10*j,map);
                    if (a==100*i+10*j+k){
                        return maps;
                    }
                }
            }
        }
        return maps;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateRelZQEnabType(RelZQ relZQ) {
        if (relZQ.getEnabType()==0){
            //更新启用时间
            relZQ.setEnabTm(new Date());
            //开启需要先将其他曲线的状态改为1
            try {
                relZQMapper.updateRelZQByCodeUnCurvNm(relZQ);
                int sl = relZQMapper.updateRelZQByCodeAndCurvNm(relZQ);
                if ( sl > 0) {
                    return 1;
                } else {
                    return 0;
                }
            }catch (Exception e){
                return 0;
            }
        }
        //将启动的曲线启动时间和启动状态更新
        else {
            //关闭启动，启动状态后改为0
            try {
                int sl=   relZQMapper.updateRelZQByCodeAndCurvNm(relZQ);
                return sl;
            }catch (Exception e){
                return 0;
            }

        }
    }

    @Override
    public RelZQ selQXByStatCdAndCurvNm(String statCd, String curvNm) {
        return relZQMapper.selQXByStatCdAndCurvNm(statCd,curvNm);
    }

    /**
     * 导出excel
     */
    @Override
    public void exportExcel(HttpServletResponse  response) throws IOException {
        InputStream inp = this.getClass().getClassLoader().getResourceAsStream("static/file/水位流量率定表.xlsx");
        XSSFWorkbook wb = new XSSFWorkbook(inp);
        OutputStream os = response.getOutputStream();
        wb.write(os);
        inp.close();
        os.close();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean importRelZQList(List<RelZQ> relZQList) {
        //先设置水位为0
        RelZQ relZQ=new RelZQ();
        relZQ.setCurvNm(relZQList.get(0).getCurvNm());
        relZQ.setStatCd(relZQList.get(0).getStatCd());
        relZQ.setSiltDepth(relZQList.get(0).getSiltDepth());
        relZQ.setNt(relZQList.get(0).getNt());
        relZQ.setCurLevel(new BigDecimal("0"));
        relZQ.setCurFlow(new BigDecimal("0"));
        relZQ.setRank(2);//导入默认是1阶
        relZQList.add(relZQ);
        //先将list按水位进行排序
        relZQList= relZQList.stream().sorted(Comparator.comparing(RelZQ::getCurLevel)).collect(Collectors.toList());
        RelZQ relZQCount= countMap(relZQList);

        double k1=0;
        double k2=0;
        double k3=0;
        double k4=0;
        double k5=0;
        double b=0;
        if (!StringUtils.isEmpty(relZQCount.getK1())){
            k1=Double.parseDouble(relZQCount.getK1());
        }
        if (!StringUtils.isEmpty(relZQCount.getK2())){
            k2=Double.parseDouble(relZQCount.getK2());
        }
        if (!StringUtils.isEmpty(relZQCount.getK3())){
            k3=Double.parseDouble(relZQCount.getK3());
        }
        if (!StringUtils.isEmpty(relZQCount.getK4())){
            k4=Double.parseDouble(relZQCount.getK4());
        }
        if (!StringUtils.isEmpty(relZQCount.getK5())){
            k5=Double.parseDouble(relZQCount.getK5());
        }
        if (!StringUtils.isEmpty(relZQCount.getB())){
            b=Double.parseDouble(relZQCount.getB());
        }

        List<RelZQ> relZQListNew=new ArrayList<>();
        for (int i = 0; i <= relZQList.size(); i++) {
            if(i + 1 >= relZQList.size()){
                relZQListNew.add(relZQList.get(i));
                break;
            }
            //先查两条数据然后计算K,b
            relZQListNew.addAll(show(relZQList.get(i),relZQList.get(i+1),i));
        }
        //设置最大水位为渠深(m)
        //查询断面渠深
        BigDecimal topz = relZQMapper.selCrossHByStatCd(relZQList.get(0).getStatCd());
        List<RelZQ> relZQS=new ArrayList<>();
        Date date=new Date();
        String statCd=relZQList.get(0).getStatCd();
        String curNm=relZQList.get(0).getCurvNm();
        BigDecimal silt=relZQList.get(0).getSiltDepth();
        String nt=relZQList.get(0).getNt();
        for (int i = 0; i <relZQListNew.size() ; i++) {
            RelZQ relZQNeW=new RelZQ();
            relZQNeW.setStatCd(statCd);
            relZQNeW.setCurvNm(curNm);
            relZQNeW.setRank(2);
            relZQNeW.setSiltDepth(silt);
            relZQNeW.setEnabType(0);
            relZQNeW.setNt(nt);
            relZQNeW.setTopZ(topz);
            relZQNeW.setBotZ(new BigDecimal("0.0"));
            relZQNeW.setK1(relZQCount.getK1());
            relZQNeW.setK2(relZQCount.getK2());
            relZQNeW.setK3(relZQCount.getK3());
            relZQNeW.setK4(relZQCount.getK4());
            relZQNeW.setK5(relZQCount.getK5());
            relZQNeW.setB(relZQCount.getB());
            relZQNeW.setCurLevel(relZQListNew.get(i).getCurLevel());
            relZQNeW.setCurFlow(relZQListNew.get(i).getCurFlow());
            relZQNeW.setEnabTm(date);
            relZQNeW.setPtNo(String.valueOf(i+1));
            relZQNeW.setInsertTime(date);
            relZQS.add(relZQNeW);
        }
        //判断上传的水位小于最大水位，则新增计算水位到最大水位
        if (relZQListNew.get(relZQListNew.size()-1).getCurLevel().compareTo(topz)<0){
            int s = relZQListNew.get(relZQListNew.size()-1).getCurLevel().multiply(new BigDecimal("100")).intValue()+1;
            int j=topz.multiply(new BigDecimal("100")).intValue();
            for (int i =s; i <j ; i++) {
                double c=i;
                double y=c/100;
                RelZQ relZQNeW=new RelZQ();
                relZQNeW.setStatCd(statCd);
                relZQNeW.setCurvNm(curNm);
                relZQNeW.setRank(2);
                relZQNeW.setSiltDepth(silt);
                relZQNeW.setEnabType(0);
                relZQNeW.setNt(nt);
                relZQNeW.setTopZ(topz);
                relZQNeW.setBotZ(new BigDecimal("0.0"));
                relZQNeW.setK1(relZQCount.getK1());
                relZQNeW.setK2(relZQCount.getK2());
                relZQNeW.setK3(relZQCount.getK3());
                relZQNeW.setK4(relZQCount.getK4());
                relZQNeW.setK5(relZQCount.getK5());
                relZQNeW.setB(relZQCount.getB());
                relZQNeW.setCurFlow(ArithmeticUtils.y(k1,k2,k3,k4,k5,b,y));
                relZQNeW.setCurLevel(new BigDecimal(Double.toString(y)).setScale(3,BigDecimal.ROUND_HALF_UP));
                relZQNeW.setEnabTm(date);
                relZQNeW.setPtNo(String.valueOf(i+2));
                relZQNeW.setInsertTime(date);
                relZQS.add(relZQNeW);
            }
        }
        //先把旧的类型改为不启用状态
        RelZQ relZQOld=new RelZQ();
        relZQOld.setStatCd(relZQList.get(0).getStatCd());
        relZQOld.setEnabType(1);
        relZQMapper.updateRelZQ(relZQOld);
        Boolean row = this.saveBatch(relZQS);
        return row;
    }

    /**
     * 导入公式y=kx+b
     * k=(y2 - y1) / (x2 - x1)
     * b=(y1*(x2 - x1) - x1*(y2 - y1)) / (x2 - x1)
     * 通过两个点遍历出水位x，再通过K，B计算y
     * @param w1
     * @param w2
     * @param ys
     * @return
     */
    public List<RelZQ> show(RelZQ w1, RelZQ w2,int ys){
        int w1Z= new BigDecimal(String.valueOf(100)).multiply(w1.getCurLevel()).intValue();
        int w2Z= new BigDecimal(String.valueOf(100)).multiply(w2.getCurLevel()).intValue();
        //x1
        BigDecimal mpZ1 = w1.getCurLevel();
        //y1
        BigDecimal mpQ1 = w1.getCurFlow();
        //x2
        BigDecimal mpZ2 = w2.getCurLevel();
        //y2
        BigDecimal mpQ2 = w2.getCurFlow();
        BigDecimal b= BigDecimalUtil.b(mpQ1,mpQ2,mpZ1,mpZ2);
        BigDecimal k=BigDecimalUtil.k(mpQ1,mpQ2,mpZ1,mpZ2);
        int subtract=w2Z-w1Z;
        List<RelZQ> relZQS = new ArrayList<>();
        if (ys==0){
            if (w1Z>0){
                BigDecimal xl=new BigDecimal(0);
                BigDecimal yl=new BigDecimal(0);
                //b=(y1*(x2 - x1) - x1*(y2 - y1)) / (x2 - x1)
                BigDecimal bl= BigDecimalUtil.b(xl,mpQ1,yl,mpZ1);
                //k=(y2 - y1) / (x2 - x1)
                BigDecimal kl=BigDecimalUtil.k(xl,mpQ1,yl,mpZ1);
                for (int i = 0; i < w1Z; i++) {
                    //除100得出水位
                    double c=i;
                    double z=c/100;
                    BigDecimal mpz=new BigDecimal(Double.toString(z)).setScale(3,BigDecimal.ROUND_HALF_UP);
                    RelZQ relZQ=new RelZQ();
                    //y=kx+b
                    double kx= ArithmeticUtils.mul(z,kl.doubleValue());
                    BigDecimal y = ArithmeticUtils.add(Double.toString(kx),bl.toString());
                    relZQ.setCurLevel(mpz);
                    relZQ.setCurFlow(y);
                    relZQS.add(relZQ);
                }
            }

        }
        for (int i = 0; i < subtract; i++) {
            double c=i+w1Z;
            double z=c/100;
            BigDecimal mpz=new BigDecimal(Double.toString(z)).setScale(3,BigDecimal.ROUND_HALF_UP);
            RelZQ relZQ=new RelZQ();;
            double kx= ArithmeticUtils.mul(z,k.doubleValue());
            BigDecimal y = ArithmeticUtils.add(Double.toString(kx),b.toString());
            relZQ.setCurLevel(mpz);
            relZQ.setCurFlow(y);
            relZQS.add(relZQ);
        }
        return relZQS;
    }


    /**
     * 导入计算多项式系数 k1-k5、b
     * @param relZQList
     * @return
     */
    private RelZQ countMap(List<RelZQ> relZQList){
        RelZQ relZQNew=new RelZQ();
        //计算出多项式系数
        Map<String,Double> stringDoubleMap=stringHashMap(relZQList);
        double k1=0;
        double k2=0;
        double k3=0;
        double k4=0;
        double k5=0;
        double b=0;
        for (String key : stringDoubleMap.keySet()) {
            if (key.equals("k1")){
                k1= stringDoubleMap.get(key);
            }else if (key.equals("k2")){
                k2=stringDoubleMap.get(key);
            }else if (key.equals("k3")){
                k3=stringDoubleMap.get(key);
            }else if (key.equals("k4")){
                k4=stringDoubleMap.get(key);
            }else if (key.equals("k5")){
                k5=stringDoubleMap.get(key);
            }else {
                b=stringDoubleMap.get(key);
            }
        }

        relZQNew.setK1(Double.toString(k1));
        relZQNew.setK2(Double.toString(k2));
        relZQNew.setK3(Double.toString(k3));
        relZQNew.setK4(Double.toString(k4));
        relZQNew.setK5(Double.toString(k5));
        relZQNew.setB(Double.toString(b));
        return relZQNew;
    }

//    public Map<String, Double> stringHashMap(List<RelZQ> relZQList) {
//        HashMap<String, Double> stringDoubleHashMap = new HashMap<String, Double>();
//        if (relZQList != null && relZQList.size() > 2) {
//            double[] waterlevels = new double[relZQList.size()];
//            double[] waterflows = new double[relZQList.size()];
//            for (int i = 0; i < relZQList.size(); i++) {
//                waterlevels[i] = relZQList.get(i).getCurLevel().doubleValue();
//                waterflows[i] = relZQList.get(i).getCurFlow().doubleValue();
//            }
//            stringDoubleHashMap.putAll(stringDoubleMap(waterlevels,waterflows,relZQList.get(0).getRank()));
//        }
//        return stringDoubleHashMap;
//    }

    public Map<String, Double> stringHashMap(List<RelZQ> relZQList) {
        HashMap<String, Double> stringDoubleHashMap = new HashMap<String, Double>();
        WeightedObservedPoints obs = new WeightedObservedPoints();
        if (relZQList != null && relZQList.size() > 2) {
            for (int i = 0; i < relZQList.size(); i++) {
                obs.add(relZQList.get(i).getCurLevel().doubleValue(),relZQList.get(i).getCurFlow().doubleValue());
            }

            stringDoubleHashMap.putAll(stringDoubleMap(obs,relZQList.get(0).getRank()));
        }
        return stringDoubleHashMap;
    }
    public Map<String, Double> stringDoubleMap(WeightedObservedPoints obs,Integer rank) {
        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(rank);
        // Retrieve fitted parameters (coefficients of the polynomial function).
        final double[] coefficients = fitter.fit(obs.toList());
        HashMap<String, Double> stringDoubleHashMap = new HashMap<String, Double>();
//        LeastSquareMethod eastSquareMethod =
//                new LeastSquareMethod(waterlevels,
//                        waterflows, rank+1);
//        double[] coefficients = eastSquareMethod.getCoefficient();
        switch (rank){
            case (1):
                stringDoubleHashMap.put("b", 0.0);
                stringDoubleHashMap.put("k1", new BigDecimal(Double.toString(coefficients[0])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k2", new BigDecimal(Double.toString(coefficients[1])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k3",0.0);
                stringDoubleHashMap.put("k4",0.0);
                stringDoubleHashMap.put("k5", 0.0);
                break;
            case (2):
                stringDoubleHashMap.put("b", new BigDecimal(Double.toString(coefficients[0])).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k1", new BigDecimal(Double.toString(coefficients[1])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k2", new BigDecimal(Double.toString(coefficients[2])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k3",0.0);
                stringDoubleHashMap.put("k4",0.0);
                stringDoubleHashMap.put("k5", 0.0);
                break;
            case (3):
                stringDoubleHashMap.put("b", new BigDecimal(Double.toString(coefficients[0])).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k1", new BigDecimal(Double.toString(coefficients[1])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k2", new BigDecimal(Double.toString(coefficients[2])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k3", new BigDecimal(Double.toString(coefficients[3])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k4",0.0);
                stringDoubleHashMap.put("k5", 0.0);
                break;
            case (4):
                stringDoubleHashMap.put("b", new BigDecimal(Double.toString(coefficients[0])).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k1", new BigDecimal(Double.toString(coefficients[1])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k2", new BigDecimal(Double.toString(coefficients[2])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k3", new BigDecimal(Double.toString(coefficients[3])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k4", new BigDecimal(Double.toString(coefficients[4])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k5", 0.0);
                break;
            case (5):
                stringDoubleHashMap.put("b", new BigDecimal(Double.toString(coefficients[0])).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k1", new BigDecimal(Double.toString(coefficients[1])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k2", new BigDecimal(Double.toString(coefficients[2])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k3", new BigDecimal(Double.toString(coefficients[3])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k4", new BigDecimal(Double.toString(coefficients[4])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k5", new BigDecimal(Double.toString(coefficients[5])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                break;
            default:
                stringDoubleHashMap.put("b", new BigDecimal(Double.toString(coefficients[0])).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k1", new BigDecimal(Double.toString(coefficients[1])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k2", new BigDecimal(Double.toString(coefficients[2])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k3", new BigDecimal(Double.toString(coefficients[3])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k4", new BigDecimal(Double.toString(coefficients[4])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                stringDoubleHashMap.put("k5", new BigDecimal(Double.toString(coefficients[5])).setScale(5,BigDecimal.ROUND_HALF_UP).doubleValue());
                break;

        }
        return stringDoubleHashMap;

    }
    public static void main(String[] args) {
        WeightedObservedPoints obs = new WeightedObservedPoints();
        obs.add(0.0  , 0.0     );
        obs.add(0.01 , 0.001   );
        obs.add(0.02 , 0.004   );
        obs.add(0.03 , 0.006   );
        obs.add(0.04 , 0.009  );
        obs.add(0.05 , 0.012  );
        obs.add(0.06 , 0.016  );
        obs.add(0.07 , 0.019  );
        obs.add(0.08 , 0.024  );
        obs.add(0.09 , 0.028  );
        obs.add(0.1  , 0.033  );
        obs.add(0.11 , 0.038  );
        obs.add(0.12 , 0.044  );
        obs.add(0.13 , 0.049  );
        obs.add(0.14 , 0.056  );
        obs.add(0.15 , 0.062  );
        obs.add(0.16 , 0.069  );
        obs.add(0.17 , 0.076  );
        obs.add(0.18 , 0.084  );
        obs.add(0.19 , 0.091  );
        obs.add(0.2  , 0.1    );
        obs.add(0.21 , 0.108  );
        obs.add(0.22 , 0.117  );
        obs.add(0.23 , 0.126  );
        obs.add(0.24 , 0.136  );
        obs.add(0.25 , 0.145  );
        obs.add(0.26 , 0.156  );
        obs.add(0.27 , 0.166  );
        obs.add(0.28 , 0.177  );
        obs.add(0.29 , 0.188  );
        obs.add(0.3  , 0.2    );
        obs.add(0.31 , 0.211  );
        obs.add(0.32 , 0.224  );
        obs.add(0.33 , 0.236  );
        obs.add(0.34 , 0.249  );
        obs.add(0.35 , 0.262  );
        obs.add(0.36 , 0.276  );
        obs.add(0.37 , 0.289  );
        obs.add(0.38 , 0.304  );
        obs.add(0.39 , 0.318  );

        // Instantiate a third-degree polynomial fitter.
        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(2);

        // Retrieve fitted parameters (coefficients of the polynomial function).
        final double[] coeff = fitter.fit(obs.toList());
        String fun = "f(x) = ";
        for (int i = coeff.length - 1; i >= 0; i--) {
            String add = coeff[i] > 0 ? "+" : "";
            String x = i > 0 ? "x^" + i : "";
            if (i == coeff.length - 1) {
                fun += (coeff[i] + x);
            } else {
                fun += (add + coeff[i] + x);
            }
        }
        System.out.println("Function is: " + fun);
    }
//    public static void main(String[] args) {
//        LeastSquareMethod eastSquareMethod =
//                new LeastSquareMethod(new double[] {0.0,
//                        0.01 ,
//                        0.02 ,
//                        0.03 ,
//                        0.04 ,
//                        0.05 ,
//                        0.06 ,
//                        0.07 ,
//                        0.08 ,
//                        0.09 ,
//                        0.1  ,
//                        0.11 ,
//                        0.12 ,
//                        0.13 ,
//                        0.14 ,
//                        0.15 ,
//                        0.16 ,
//                        0.17 ,
//                        0.18 ,
//                        0.19 ,
//                        0.2   },
//                        new double[] {0.0   ,
//                                0.001 ,
//                                0.004 ,
//                                0.006 ,
//                                0.009 ,
//                                0.012 ,
//                                0.016 ,
//                                0.019 ,
//                                0.024 ,
//                                0.028 ,
//                                0.033 ,
//                                0.038 ,
//                                0.044 ,
//                                0.049 ,
//                                0.056 ,
//                                0.062 ,
//                                0.069 ,
//                                0.076 ,
//                                0.084 ,
//                                0.091 ,
//                                0.1 }, 2);
//        double[] coefficients = eastSquareMethod.getCoefficient();
//        System.out.println(coefficients[0]+"1111"+coefficients[1]);
//    }
}
